package samples

import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.runTest
import org.junit.Test
import kotlin.system.measureTimeMillis

/**
 *
 * @author mph
 * @date 2025/1/9
 */
/**
 * launch和async都会启动一个非阻塞的协程（并发的），不同的是launch会返回一个Job,async会返回一个Deferred<Result>（同时他也是Job），可以调用await来等待异步结果
 */
@OptIn(ExperimentalCoroutinesApi::class)
class SuspendTest {

    @Test
    fun testSuspend() = runTest {
        val time = measureTimeMillis {
            val one = doSomethingUsefulOne()
            val two = doSomethingUsefulTwo()
            println("The answer is ${one + two}")
        }
        println("Completed in $time ms")
        launch {
            delay(300L)
            println("launch1")
        }
        launch {
            delay(300L)
            println("launch2")
        }
        println("launch end")
    }

    private suspend fun doSomethingUsefulOne(): Int {
        delay(1000L) // pretend we are doing something useful here
        return 13
    }

    private suspend fun doSomethingUsefulTwo(): Int {
        delay(1000L) // pretend we are doing something useful here, too
        return 29
    }

    private suspend fun doSomethingUsefulThree(): Int {
        delay(1000L) // pretend we are doing something useful here, too
        return 17
    }

    @Test
    fun testAsync() = runTest {
        val time = measureTimeMillis {
            val one = async(start = CoroutineStart.LAZY) {
                println("One") //指定了CoroutineStart.LAZY后，该代码会等到await或者start方法调用时才会触发
                doSomethingUsefulOne()
            }
            val three = async(start = CoroutineStart.LAZY) {
                println("Three") //指定了CoroutineStart.LAZY后，该代码会等到await或者start方法调用时才会触发
                doSomethingUsefulThree()
            }
            //没有指定start会立刻执行（但是注意会有协程创建执行的延迟时间）
            val two = async {
                println("Two")
                doSomethingUsefulTwo()
            }
            delay(300L) //给async-two启动执行一个准备时间，“Two”会先于“Middle”打印
            println("Middle")
            one.start() //启动async执行
            delay(300L)  //给start启动async执行一个准备时间，“One”会先于“After”打印
            println("After")
            //注意这里的async-three是lazy的，但是它没有提前调用start函数，这就意味着在这里调用await的时候才开始执行，而前面的one.await()正在等待结果返回，所以three会一直
            // 等到其返回后才会被执行，因此此时就变成了串行执行
            println("Result is ${one.await() + three.await() + two.await()}")
        }
        println("Completed in $time ms")
    }

    /**
     * 错误实例展示，使用GlobalScope.async，而非结构化并发
     * 在实际开发中这种方式是被强烈制止的
     */
    // The result type of somethingUsefulOneAsync is Deferred<Int>
    @OptIn(DelicateCoroutinesApi::class)
    fun somethingUsefulOneAsync() = GlobalScope.async {
        delay(2000L)
        doSomethingUsefulOne()
        println("somethingUsefulOneAsync end!")
    }

    // The result type of somethingUsefulTwoAsync is Deferred<Int>
    @OptIn(DelicateCoroutinesApi::class)
    fun somethingUsefulTwoAsync() = GlobalScope.async {
        delay(3000L)
        doSomethingUsefulTwo()
        println("somethingUsefulTwoAsync end!")
    }

    @Suppress("UNREACHABLE_CODE", "CAST_NEVER_SUCCEEDS")
    @Test
    fun testAsyncError() {
        val time = measureTimeMillis {
            // we can initiate async actions outside of a coroutine
            val one = somethingUsefulOneAsync()
            val two = somethingUsefulTwoAsync()
            // but waiting for a result must involve either suspending or blocking.
            // here we use `runBlocking { ... }` to block the main thread while waiting for the result
            //假设在这里抛出了一个异常，那么当前线程会被阻断而结束，也就是说下面的await不会被执行到，但是上面调用的somethingUsefulOneAsync和somethingUsefulTwoAsync
            // 仍然在执行，因为它们在GlobalScope作用域的协程中，不属于当前线程的子协程，所以不会被终止，这就是不被允许这么使用的原因
            try {
                throw RuntimeException("test")
                runBlocking {
                    println("The answer is ${one.await()}")
                    println("The answer is ${two.await()}")
                }
            } catch (e: RuntimeException) {
            }
            println("One isActive: ${one.isActive}")
            println("Two isActive: ${two.isActive}")
        }
        println("Completed in $time ms")
    }

    /**
     * 结构化并发（最佳）不存在生命周期不一致的问题
     */
    @Test
    fun testCorrectConcurrency() = runTest  {
        try {
            failedConcurrentSum()
        } catch(e: ArithmeticException) {
            println("Computation failed with ArithmeticException")
        }
    }

    suspend fun failedConcurrentSum(): Int = coroutineScope {
        val one = async<Int> {
            try {
                delay(Long.MAX_VALUE) // Emulates very long computation
                42
            } finally {
                println("First child was cancelled")
            }
        }
        val two = async<Int> {
            println("Second child throws an exception")
            throw ArithmeticException()
        }
        //two先抛出异常，因为是结构化并发，所以其父协程也会被取消，父协程被取消时会自动先取消所有的子协程，所以输出内容是：
        // Second child throws an exception
        // First child was cancelled
        // Computation failed with ArithmeticException
        one.await() + two.await()
    }
}